﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharpExt.Collections
{
    /// <summary>
    /// Questa classe puo' essere utilizzata per allocare
    /// dei buffer (byte[]) in modo efficiente.
    /// 
    /// L'idea e' la seguente: invece di allocare esplicitamente 
    /// un buffer di una determinata dimensione, viene richiesto
    /// a questa classe.
    /// 
    /// Questa fornisce un buffer che ha come dimensione una potenza 
    /// di 2 che e' >= alla dimensione richiesta.
    /// 
    /// Quando il buffer non serve piu', viene rilasciato e questa
    /// classe si occupa di inserirlo in un'opportuna coda per un
    /// utilizzo successivo
    /// 
    /// Nota: usare Queue[T] o List[T] non cambia nulla
    /// 
    /// Nota: L'uso di Acquire[T](N) e' molto piu' pesante di new T[N]
    /// </summary>
    public static class Allocator<T>
    {
        #region Private Data

        private static Queue<T[]>[] _buckets = new Queue<T[]>[32];

        static Allocator()
        {
            for (int i = 0; i < _buckets.Length; ++i )
            {
                _buckets[i] = new Queue<T[]>();
            }
        }

        #endregion

        #region Operations

        public static T[] Allocate(int size)
        {
            int index = select(size);
            Queue<T[]> bucket = _buckets[index];

            lock (_buckets)
            {
                return bucket.Count != 0 ? bucket.Dequeue() : new T[2<<index];
            }
        }

        public static void Release(T[] buffer)
        {
            int index = select(buffer.Length);
            Queue<T[]> bucket = _buckets[index];

            lock (_buckets)
            {
                bucket.Enqueue(buffer);
            }
        }

        private static int select(int size)
        {
            int index = 0, length = 1;
            while (length < size)
            {
                ++index;
                length <<= 1;
            }
            return index;
        }

        #endregion
    }

}
